package data.join.com.utils;

import android.text.TextUtils;
import android.util.Log;

import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.storage.KeyGenerator;
import com.qiniu.android.storage.UpCancellationSignal;
import com.qiniu.android.storage.UpCompletionHandler;
import com.qiniu.android.storage.UpProgressHandler;
import com.qiniu.android.storage.UploadManager;
import com.qiniu.android.storage.UploadOptions;
import com.qiniu.android.storage.persistent.FileRecorder;
import com.qiniu.android.utils.UrlSafeBase64;

import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import data.join.com.application.RecordApp;
import data.join.com.network.RetrofitManager;
import data.join.com.network.gson.UploadFileToken;
import retrofit2.Call;
import retrofit2.Response;

/**
 * Created by wenlong on 15-12-29.
 */
public class QiniuApi {

    public static final int UPLOAD_WHAT_COMPLETE = 1000;
    public static final int UPLOAD_WHAT_PROGRESS = 1001;
    public static final int UPLOAD_WHAT_CANCEL = 1002;

    public static final int UPLOAD_MIN_TIME = 20*1000;
    public static final int UPLOAD_MIN_SPEED = 40;

    public static final String TAG = QiniuApi.class.getSimpleName();

    public final String URL = "http://o79is4ka4.bkt.clouddn.com/";

    private static String AccessKey = "MHOnpLsE1vwhGk08Qcmb3z86tmz0MVSMCzS-VLod";
    private static String SecretKey = "RMTfSQUKZ_fAx3FqRo0iHfhlSSZQmwLnbiYyDUdz";

    public interface UploadListern {
        public void OnUploadChange(int what, Object obj);
    }



    private static QiniuApi mQiniuApi = new QiniuApi();
    UploadManager uploadManager;

    boolean isCancelled = false;

    CountDownLatch mCountDownLatch;

    UploadResult uploadResult;

    long fileLength;
    Double startOffset;
    long startTime;
    double averageSpeed;
    double currentPercent;

    public static class UploadResult{
        public String cloudKey;
        public String cloudHash;
        public String persistentId;
    }

    private QiniuApi() {
        createUploadManager();
    }

    public static QiniuApi getDefault() {
        return mQiniuApi;
    }

    public UploadManager getUploadManager() {
        return uploadManager;
    }

    public void startUpload(String path, String token, String key, final UploadListern l) {
        //srcPath = "/sdcard/video.mp4";
        MyLog.D(TAG, "startUpload srcPath=" + path);
        MyLog.D(TAG, "startUpload token=" + token);

        isCancelled = false;
        getUploadManager().put(path, key, token,
                new UpCompletionHandler() {
                    @Override
                    public void complete(String s, ResponseInfo responseInfo, JSONObject jsonObject) {
                        if (l != null) {
                            if (jsonObject == null && isCancelled)
                                l.OnUploadChange(UPLOAD_WHAT_CANCEL, jsonObject);
                            else
                                l.OnUploadChange(UPLOAD_WHAT_COMPLETE, jsonObject);
                        }
                        if (jsonObject != null) {
                            MyLog.D(TAG, "jsonObject =" + jsonObject.toString());
                        } else {
                            MyLog.D(TAG, "UpCompletionHandler jsonObject is NULL");
                        }
                    }
                },
                new UploadOptions(null, null, false,
                        new UpProgressHandler() {
                            public void progress(String key, double percent) {
                                if (l != null)
                                    l.OnUploadChange(UPLOAD_WHAT_PROGRESS, percent);
                                MyLog.D(TAG, "UpProgressHandler percent=" + percent + ",key=" + key);
                            }
                        },
                        new UpCancellationSignal() {
                            public boolean isCancelled() {
                                return isCancelled;
                            }
                        }
                )
        );
    }

    public void setCancelled() {
        isCancelled = true;
    }

    public static UploadFileToken getQiniuToken(String filePath,String type) {
        UploadFileToken _uploadToken = null;

        //_uploadToken = FileUtilSDK.getQiniuToken(SecretKey,AccessKey);

        String fileName = generateTokenName(filePath);

        Call<UploadFileToken> fileTokenCall = RetrofitManager.getApiService().getToken(fileName,type);

        try {
            Response<UploadFileToken> response = fileTokenCall.execute();

            if(response.isSuccessful()){
                UploadFileToken uploadFileToken = response.body();
                if(uploadFileToken != null && uploadFileToken.data != null){
                    _uploadToken = uploadFileToken;
                    if(TextUtils.isEmpty(_uploadToken.getFileKey())){
                        _uploadToken.data.key = fileName;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return _uploadToken;
    }

    public static UploadFileToken getQiniuLogToken(String filePath) {
        UploadFileToken _uploadToken = null;

        String fileName = new File(filePath).getName();

        String imei = QuickShPref.getInstance().getString(QuickShPref.DeviceImei);

        if(fileName.contains(imei) == false){
            fileName = imei+"_"+fileName;
        }

        Call<UploadFileToken> fileTokenCall = RetrofitManager.getApiService().getToken(fileName,null);

        try {
            Response<UploadFileToken> response = fileTokenCall.execute();

            if(response.isSuccessful()){
                UploadFileToken uploadFileToken = response.body();
                if(uploadFileToken != null && uploadFileToken.data != null){
                    _uploadToken = uploadFileToken;
                    _uploadToken.data.key = fileName;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return _uploadToken;
    }

    public synchronized UploadResult startUploadAsync(String path, UploadFileToken uploadFileToken) {
        MyLog.D(TAG, "startUpload srcPath=" + path);

        if(checkUploadParamEmpty(path,uploadFileToken)){
            return null;
        }

        isCancelled = false;
        uploadResult = null;
        startOffset = null;
        fileLength = new File(path).length();

        mCountDownLatch = new CountDownLatch(1);

        UploadManager uploadManager = getUploadManager();

        uploadManager.put(path, uploadFileToken.getFileKey(), uploadFileToken.getToken(),
                new UpCompletionHandler() {
                    @Override
                    public void complete(String s, ResponseInfo responseInfo, JSONObject jsonObject) {

                        if (responseInfo != null && responseInfo.isOK() && jsonObject != null && !TextUtils.isEmpty(jsonObject.optString("key"))) {
                            uploadResult = new UploadResult();
                            uploadResult.cloudKey = jsonObject.optString("key");
                            uploadResult.cloudHash = jsonObject.optString("hash");
                            uploadResult.persistentId = jsonObject.optString("persistentId");
                            MyLog.D(TAG, "startUploadAsync complete:" + jsonObject.toString());
                        }else if(jsonObject != null){
                            MyLog.D(TAG, "startUploadAsync fail:" + jsonObject.toString());
                        }else{
                            MyLog.D(TAG, "startUploadAsync fail: jsonObject is NULL");
                        }
                        mCountDownLatch.countDown();
                    }
                },
                new UploadOptions(null, null, false,
                        new UpProgressHandler() {
                            public void progress(String key, double percent) {
                                refreshSpeed(percent);
                            }
                        },
                        new UpCancellationSignal() {
                            public boolean isCancelled() {
                                return isCancelled;
                            }
                        }
                )
        );
        try {
            while(mCountDownLatch.getCount() >= 1) {
                mCountDownLatch.await(20, TimeUnit.SECONDS);
                checkoutSpeed();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            isCancelled = true;
        }

        return uploadResult;
    }


    private void checkoutSpeed(){
        if(startOffset == null){
            isCancelled = true;
        }else if(averageSpeed <= UPLOAD_MIN_SPEED && currentPercent < 0.8){
            isCancelled = true;
        }
        MyLog.D(TAG,"checkoutSpeed startOffset="+startOffset+",averageSpeed="+averageSpeed+",currentPercent="+currentPercent+",isCancelled="+isCancelled);
    }

    private void refreshSpeed(double percent){
        if(startOffset == null){
            startOffset = percent;
            startTime = System.currentTimeMillis();
            averageSpeed = -1;
            MyLog.D(TAG,"refreshSpeed start,percent="+percent);
        }else{
            double deltaSize = (percent - startOffset)*fileLength;
            long deltaTime = System.currentTimeMillis() - startTime;
            if(deltaTime > 0) {
                averageSpeed = deltaSize / deltaTime;
                MyLog.D(TAG, "refreshSpeed percent=" + percent + ",deltaTime=" + (deltaTime / 1000f) + "s" + ",averageSpeed=" + averageSpeed);
            }
        }
        currentPercent = percent;
    }

    private void createUploadManager(){
        try {
            this.uploadManager = new UploadManager(new FileRecorder(RecordApp.getDefault().getFilesDir() + "/QiniuAndroid"),
                    new KeyGenerator() {
                        // 指定一个进度文件名，用文件路径和最后修改时间做hash
                        @Override
                        public String gen(String key, File file) {
                            String recorderName = System.currentTimeMillis() + ".progress";
                            try {
                                recorderName = UrlSafeBase64.encodeToString(Tools.sha1(file.getAbsolutePath() + ":" + file.lastModified())) + ".progress";
                            } catch (NoSuchAlgorithmException e) {
                                Log.e("QiniuLab", e.getMessage());
                            } catch (UnsupportedEncodingException e) {
                                Log.e("QiniuLab", e.getMessage());
                            }
                            return recorderName;
                        }
                    });
        } catch (Exception e) {
            Log.e("QiniuLab", e.getMessage());
        }
    }

    private static String generateTokenName(String filePath){
        String imei = QuickShPref.getInstance().getString(QuickShPref.DeviceImei);
        String tmp;
        if(!TextUtils.isEmpty(filePath)) {
            long lastModify = System.currentTimeMillis();

            try {
                lastModify = new File(filePath).lastModified();
            }catch (Exception e){
                e.printStackTrace();
            }

            tmp = CryptoUtils.MD5Encode(filePath + lastModify);
        }else{
            tmp = ""+System.currentTimeMillis();
        }

        return imei + tmp;
    }

    public static boolean checkUploadParamEmpty(String path, UploadFileToken uploadFileToken){
        boolean ret = false;
        if (TextUtils.isEmpty(path)) {
            MyLog.D(TAG, "startUploadAsync srcPath is isEmpty,return null");
            ret = true;
        }else if(new File(path).exists() == false){
            MyLog.D(TAG, "startUploadAsync file not exists,return null");
            ret = true;
        }

        if (uploadFileToken == null) {
            MyLog.D(TAG, "startUploadAsync uploadFileToken is null");
            ret = true;
        }else {
            if (TextUtils.isEmpty(uploadFileToken.getToken())) {
                MyLog.D(TAG, "startUploadAsync token is isEmpty,return null");
                ret = true;
            }

            if (TextUtils.isEmpty(uploadFileToken.getFileKey())) {
                MyLog.D(TAG, "startUploadAsync token is isEmpty,return null");
                ret = true;
            }


            MyLog.D(TAG, "startUploadAsync getToken is "+uploadFileToken.getToken());
            MyLog.D(TAG, "startUploadAsync getFileKey is "+uploadFileToken.getFileKey());
        }

        return ret;
    }
}
